//实现一个compose函数
function compose(...fn){
    if(!fn.length) return (v) => v
    if(fn.length === 1) return fn[0]
    return fn.reduce((pre, cur) => 
        (...args) => 
            pre(cur(...args)))
}

//用法如下
function fn1(x){
    return x + 1
}

function fn2(x){
    return x + 2
}

function fn3(x){
    return x + 3
}

function fn4(x){
    return x * 4
}

const a = compose(fn1,fn2,fn3,fn4)
console.log(a(1))

// setTimeout 模拟实现 setInterval(带清除定时器的版本)
//题目描述： setInterval 用来实现循环定时调用 可能会存在一定的问题 能用setTimeout解决吗
function mySetInterval(fn,wait){
    let timer = null
    function interval(){
        timer = setTimeout(() => {
            fn()
            interval()
        }, wait)
    }
    interval()
    return {
        cancel: () => {
            clearTimeout(timer)
        }
    }
}
// 调用
// let b = mySetInterval(()=>{
//     console.log('88888')
// }, 1000)

// b.cancel()

// 拓展：反过来使用setInterval模拟实现setTimeout
const mySettimeout = (fn,wait) => {
    const timer = setInterval(()=>{
        clearInterval(timer)
        fn()
    }, wait)
}

// mySettimeout(()=>{
//     console.log('23344444')
// },1000)

// 拓展思考：为什么要用setTimeout 模拟实现setInterval？ setInterval的缺陷是什么？（见timer.js）

//数组去重
function uniqueArr(arr){
    // 方法一
    // arr =  [...new Set(arr)]
    // 方法二
    arr =  Array.from(new Set(arr))
   return arr
}

// 数组扁平化
// 方法一： 迭代思想
function flatter(arr){
    if(!arr.length) return
    while(arr.some(item=> Array.isArray(item))){
        arr = [].concat(...arr)
    }
    return arr
}
//方法二：递归方式
function flatter1(arr){
    if(!arr.length) return
    return arr.reduce((pre,cur)=>
        Array.isArray(cur) ? [...pre,...flatter1(cur)] : [...pre, cur]
        , []
    )
}

//寄生组合继承
function Parent(name){
    this.name = name
    this.say = () => {
        console.log('1111')
    }
}

Parent.prototype.play = () => {
    console.log('222')
}

function Children(name){
    Parent.call(this)
    this.name = name
}

Children.prototype = Object.create(Parent.prototype)
Children.prototype.constructor = Children

// let child = new Children('333')
// console.log(child.name)
// child.say()
// child.play()

// 实现有并行限制的Promise调度器
//题目：js实现一个带并发限制的异步调度器，保证同时运行的任务最多有两个
class Scheduler {
    constructor(limit){
        this.queue = []
        this.maxCount = limit
        this.runCounts = 0
    }

    add(time,order){
        const promiseCreator = () => {
            return new Promise((resolve,reject) => {
                setTimeout(() => {
                    console.log(order)
                    resolve()
                },time)
            })
        }
        this.queue.push(promiseCreator)
    }

    taskStart(){
        for(let i = 0; i < this.maxCount; i ++){
            this.request()
        }
    }

    request(){
        if(this.queue.length === 0  || this.runCounts >= this.maxCount){
            return
        }
        this.runCounts ++
        this.queue.shift()().then(()=>{
            this.runCounts --
            this.request()
        })
    }
}

// const scheduler = new Scheduler(2)
// const addTask = (time,order) => {
//     scheduler.add(time,order)
// }
// addTask(2000,'1')
// addTask(1000,'2')
// addTask(1000, '3')
// scheduler.taskStart();

//new操作符：手写new操作符实现
function myNew(fn, ...args){
    let obj = Object.create(fn.prototype)
    let res = fn.call(obj, ...args)
    if(res && (typeof res === 'object' || typeof res === 'function')){
        return res
    }
    return obj
}

/**
 * 结合new操作符做了什么来看
 * 1、首先创建了一个新对象
 * 2、设置原型，将对象的原型设置为函数的prototype对象
 * 3、让函数的this指向这个对象，执行构造函数的代码（为这个新对象添加属性）
 * 4、判断函数的返回值类型，如果是值类型，返回创建的对象。
 */

//instanceof: 手写instanceof操作符实现
function myInstanceof(left,right){
    while(true){
        if(left._proto_ === null){
            return false
        }
        if(left._proto_ === right.prototype){
            return true
        }
        left = left._proto_
    }
}

//柯里化：
/**
 * 题目描述：柯里化（Currying），又称部分求值（Partial Evaluation），是把接受多个参数的函数变换成接受一个
 * 单一参数（最初函数的第一个参数）的函数，并且返回接受余下的参数而且返回结果的新函数的技术。核心思想是把多参数
 * 传入的函数拆成单参数（或部分）函数，内部再返回调用下一个单参数（或部分）函数，依次处理剩余的参数
 */

function currying(fn,...args){
    const length = fn.length
    let allArgs = [...args]
    const res = (...newArgs) => {
        allArgs = [...args, ...newArgs]
        if(allArgs.length === length){
            return fn(...allArgs)
        } else {
            return res
        }
    }
    return res
}

//冒泡排序
function bubbleSort(arr){
    for(let i = 0; i < arr.length - 1; i ++){
        for(let j = 0; j < arr.length - i - 1; j ++){
            if(arr[j] > arr[j+1]){
                [arr[j+1],arr[j]] = [arr[j],arr[j+1]]
            }
        }
    }
    return arr
}

// 选择排序
function selectSort(arr){
  const length = arr.length
  let minIndex;
  for(let i = 0; i < length - 1; i ++){
    minIndex = i
    for(let j = i + 1; j < length; j ++){
        if(arr[j] < arr[minIndex]){
            minIndex = j
        }
    }
    if(minIndex !== i){
        [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
    }
  }
  return arr
}

// 插入排序
function insertSort(arr){
    for(let i = 1; i < arr.length; i ++){
        let j = i
        let target = arr[j]
        while(j > 0 && arr[j - 1] > target){
            arr[j] = arr[j - 1]
            j--
        }
        arr[j] = target
    }
    return arr
}
// console.log('insertSort',insertSort([2,5,9,3,7,0]))

//快排
function quickSort(arr){
    if(arr.length < 2){
        return arr
    }
    const cur = arr[arr.length - 1]
    const left = arr.filter((v,i)=> v <= cur && i !== arr.length - 1)
    const right = arr.filter(v => v > cur)
    return [...quickSort(left), cur, ...quickSort(right)]
}

// console.log('quickSort',quickSort([2,5,9,3,7,0]))

//归并排序
function merge(left,right){
    let res = []
    let i = 0
    let j = 0
    while(i < left.length && j < right.length){
        if(left[i] < right[j]){
            res.push(left[i])
            i++
        } else {
            res.push(right[j])
            j++
        }
    }
    if(i < left.length){
        res.push(...left.slice(i))
    } else {
        res.push(...right.slice(j))
    }
    return res
}

function mergeSort(arr){
    if(arr.length < 2){
        return arr
    }
    const mid = Math.floor(arr.length / 2)
    const left = mergeSort(arr.slice(0,mid))
    const right = mergeSort(arr.slice(mid))
    return merge(left,right)
}
// console.log('mergeSort',mergeSort([2,5,9,3,7,0]))

// 二分查找
function search(arr,target,start,end){
    let targetIndex = -1;
    let mid = Math.floor((start + end) / 2)
    if(arr[mid] === target){
        targetIndex = mid
        return targetIndex
    }
    if(start >= end){
        return targetIndex
    }
    if(arr[mid] < target){
        return search(arr, target, mid + 1, end)
    } else {
        return search(arr, target, start, mid - 1)
    }
}

const dataArr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const position = search(dataArr, 6, 0, dataArr.length - 1);
if (position !== -1) {
  console.log(`目标元素在数组中的位置:${position}`);
} else {
  console.log("目标元素不在数组中");
}




